#include "MpiEnvironment.h"
#include "MpiException.h"

#include <cassert>
#include <iostream>
#include <sstream>

#include "mpi.h"

using namespace SG::Algebra;

//=============================================================================
// MpiEnvironment

MpiEnvironment::MpiEnvironment (int argc, char** argv)
{
    if (!initialized ())
    {
        MPI_CHECK_RESULT (MPI_Init, (&argc, &argv));
        mInitialized = true;
    }
}

MpiEnvironment::~MpiEnvironment ()
{
    // Call MPI_Finalize() if I has initialized the MPI execution environment.
    // If MPI was initiated externally by either the user or another software package,
    // the user is responsible for calling MPI_Finalize().
    if (mInitialized)
    {
        if (!finalized ())
        {
            MPI_CHECK_RESULT (MPI_Finalize, ());
        }
    }
}

bool MpiEnvironment::initialized ()
{
    int mpi_is_initialized;
    int mpi_err = MPI_Initialized (&mpi_is_initialized);
    return (mpi_err == MPI_SUCCESS) && mpi_is_initialized;
}
/// Return true if MPI has been finalized.
bool MpiEnvironment::finalized ()
{
    int mpi_is_finalized;
    int mpi_err = MPI_Finalized (&mpi_is_finalized);
    return (mpi_err == MPI_SUCCESS) && mpi_is_finalized;
}

int MpiEnvironment::world_rank ()
{
    int world_rank;
    MPI_CHECK_RESULT (MPI_Comm_rank, (MPI_COMM_WORLD, &world_rank));
    return world_rank;
}

int MpiEnvironment::world_size ()
{
    int world_size;
    MPI_CHECK_RESULT (MPI_Comm_size, (MPI_COMM_WORLD, &world_size));
    return world_size;
}

std::string MpiEnvironment::processor_name ()
{
    char name[MPI_MAX_PROCESSOR_NAME];
    int  len;

    MPI_CHECK_RESULT (MPI_Get_processor_name, (name, &len));
    return std::string (name, len);
}

std::string MpiEnvironment::version ()
{
    int major, minor;
    MPI_CHECK_RESULT (MPI_Get_version, (&major, &minor));

    std::stringstream ss;
    ss << major << "." << minor;
    return ss.str();
}

void MpiEnvironment::abort (int errcode)
{
    MPI_CHECK_RESULT (MPI_Abort, (MPI_COMM_WORLD, errcode));
}